#include <stdlib.h>
#include <stdio.h>
#include "collaboration.h"
#include "MIDataAccessor.h"
#include "MIUser.h"

MIDataAccessor_impl::MIDataAccessor_impl()
{
	m_reader.createLog();
	m_applications = m_reader.get();
}

MIDataAccessor_impl::~MIDataAccessor_impl()
{

}

int MIDataAccessor_impl::getUser(Collaboration::MIApplication& app, const ::std::string& user)
{
	unsigned int i;
	for(i=0; i<app.users.size(); i++)
	{
		if (app.users[i].name == user)
		{
			return i;
		}
	}

	return -1;
}

int MIDataAccessor_impl::getRole(Collaboration::MIApplication& app, const ::std::string& role)
{
	unsigned int i;
	for(i=0; i<app.roles.size(); i++)
	{
		if (app.roles[i].name == role)
		{
			return i;
		}
	}

	return -1;
}

int MIDataAccessor_impl::getApplicationPos(const ::std::string& app)
{	
	unsigned int i;
	for(i=0; i<m_applications.size(); i++)
	{
		if (m_applications[i].name == app)
		{
			return i;
		}
	}

	return -1;
}

Collaboration::ListOfApplications MIDataAccessor_impl::getApplications(const Ice::Current& c)
{
	return m_applications;
}

bool MIDataAccessor_impl::addApplication(const ::std::string& app, const Ice::Current& c)
{	
	int pos = getApplicationPos(app);
	if (pos == -1) //solo agregar si no existe ya
	{
		Collaboration::MIApplication aux;
		aux.name = app;
		m_applications.push_back(aux);
		
		return true;
	}
	
	else return false;
}

bool MIDataAccessor_impl::removeApplication(const ::std::string& app, const Ice::Current& c)
{
	int pos = getApplicationPos(app);
	Collaboration::MIApplication temp;
	if (pos != -1)
	{
		temp = m_applications[m_applications.size()-1];
		m_applications[m_applications.size()-1] = m_applications[pos];
		m_applications[pos] = temp;
		
		m_applications.pop_back();
		
		return true;
	}
	
	else return false;
}

Collaboration::MIConnection MIDataAccessor_impl::login(const ::std::string& app, 
														const ::std::string& user, 
														const ::std::string& pass,
														const Ice::Current& c)
{
	unsigned int i;
	::std::string message;
	bool error = false;
	Collaboration::MIUser usr;
	Collaboration::MIApplication apl;
	Collaboration::MIConnection info_completa;
	
	int pos = getApplicationPos(app);
	int pos_usr;
	
	if (pos != -1)
	{
		apl = m_applications[pos];
		pos_usr = getUser(apl, user);
		
		if (pos_usr != -1)
		{
			usr = apl.users[pos_usr];
			if (usr.password != pass)
			{
				error = true;
				message = "Password incorrecto";
			}
				
			else if (usr.isOnline)
			{
				error = true;
				message = "Usuario ya conectado";
			}
		}
		else
		{
			error = true;
			message = "No existe el usuario";
		}
	}
	else
	{
		error = true;
		message = "La aplicacion no existe";
	}

	if (!message.empty())
	{
		info_completa.errorMessage = message;
	}
	
	if (!error)
	{
		MIUser::isOnline(usr, true);
		usr.actualRole = usr.defaultRole;

		info_completa.validLogin = true;
		info_completa.isAdmin = usr.isAdmin;
		info_completa.role = usr.defaultRole;
		info_completa.allowedRoles = allowedRoles(app, user, c);
		info_completa.connectedUsers = MIApplication::getConnectedUsersInfo(apl);
		
		Collaboration::ListOfComponents componentes = apl.components;
		
		int permisoU = -1;
		int permisoR = -1;
		::std::string componente;
		for (i = 0; i < componentes.size(); i++)
		{	
			componente = componentes[i].name;
			permisoU = getUserComponentPermissions(app, user, componente, c);
			permisoR = getRoleComponentPermissions(app, info_completa.role, componente, c);
					
			if (permisoR == -1)
			{
				if (permisoU == -1) 
					permisoU = apl.defaultPermissions;
			}
			
			else 
				if (permisoU == -1)
					permisoU = permisoR;
			else 
				if (permisoU < permisoR) 
					permisoU = permisoR;
			
			Collaboration::MIComponent ccc;
			ccc.name = componente;
			ccc.permissions = permisoU;
			
			Collaboration::ListOfComponents comp;
			comp.push_back(ccc);
			
			info_completa.components = comp;
		}
	}

	return info_completa;
}

::std::string MIDataAccessor_impl::connectUser(const ::std::string& app, 
												const ::std::string& user,
												const Ice::Current& c)
{	
	int pos = getApplicationPos(app);
	
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		return MIApplication::setConnectedUser(apl, user);
	}
	
	return "";
}

void MIDataAccessor_impl::disconnectUser(const ::std::string& app, const ::std::string& user, const Ice::Current& c)
{
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		MIApplication::setDisconnectedUser(apl, user);
	}
}

void MIDataAccessor_impl::updateUserTime(const ::std::string& app, const ::std::string& user, const Ice::Current& c)
{
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		MIApplication::updateUserTime(apl, user);
	}
}

Collaboration::MIConnection MIDataAccessor_impl::changeConnectedUserRole(const ::std::string& app, 
																		const ::std::string& user, 
																		const ::std::string& role,
																		const Ice::Current& c)
{
	unsigned int i;
	bool correcto;
	Collaboration::MIConnection info;
	Collaboration::MIUser usr;
	
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		correcto = MIApplication::setActualUserRole(apl, user, role);

		if (correcto)
		{ // No ha habido error
			pos = getUser(apl, user);
			usr = apl.users[pos];
			info.validLogin = true;
			info.role = usr.actualRole;
			info.allowedRoles = allowedRoles(app, user, c);
			
			Collaboration::ListOfStrings componentes = applicationComponents(app, c);
			int permisoU = -1;
			int permisoR = -1;
			::std::string componente;
			for (i = 0; i < componentes.size(); i++)
			{
				componente = componentes[i];
				
				permisoU = getUserComponentPermissions(app, user, componente, c);
				permisoR = getRoleComponentPermissions(app, info.role, componente, c);
						
				if (permisoR == -1)
				{
					if (permisoU == -1) 
						permisoU = apl.defaultPermissions;
				}
				else 
					if (permisoU == -1)
						permisoU = permisoR;
				else 
					if (permisoU < permisoR) 
						permisoU = permisoR;
				
				Collaboration::MIComponent ccc;
				ccc.name = componente;
				ccc.permissions = permisoU;

				info.components.push_back(ccc);
			}
		}
		
		else
		{
			info.errorMessage = "Error al cambiar el rol al usuario";
		}
	}
	
	else
	{
		info.errorMessage = "Aplicacion no encontrada";
	}
	
	return info;
}

Collaboration::ListOfUsersAndRoles MIDataAccessor_impl::connectedUsers(const ::std::string& app, const Ice::Current& c)
{
	Collaboration::ListOfUsersAndRoles vacia;
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		return MIApplication::getConnectedUsers(apl);
	}
	else return vacia;
}

Collaboration::ListOfUsers MIDataAccessor_impl::connectedUsersInfo(const ::std::string& app, const Ice::Current& c)
{
	Collaboration::ListOfUsers vacia;
	
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		return MIApplication::getConnectedUsersInfo(apl);
	}
	else return vacia;
}

Collaboration::ListOfUsers MIDataAccessor_impl::usersInfo(const ::std::string& app, const Ice::Current& c)
{
	Collaboration::ListOfUsers vacia;
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		return apl.users;
	}
	else return vacia;
}

Collaboration::ListOfRoles MIDataAccessor_impl::rolesInfo(const ::std::string& app, const Ice::Current& c)
{
	Collaboration::ListOfRoles vacia;
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		return apl.roles;
	}
	else return vacia;
}

Collaboration::MIRole MIDataAccessor_impl::roleInfo(const ::std::string& app, 
													const ::std::string& role_name, 
													const Ice::Current& c)
{
	Collaboration::MIRole vacio;
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		return apl.roles[getRole(apl, role_name)];
	}
	else return vacio;
}

Collaboration::MIUser MIDataAccessor_impl::userInfo(const ::std::string& app, 
													const ::std::string& user_name, 
													const Ice::Current& c)
{
	Collaboration::MIUser vacio;
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		return apl.users[getUser(apl, user_name)];
	}
	else return vacio;	
}

Collaboration::ListOfStrings MIDataAccessor_impl::roleUsers(const ::std::string& app, 
															const ::std::string& role,
															const Ice::Current& c)
{
	Collaboration::ListOfStrings vacio;
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		return MIApplication::getRoleUsers(apl, role);
	}
	else return vacio;
}

Collaboration::ListOfStrings MIDataAccessor_impl::nonUpdatedUsers(const ::std::string& app, const Ice::Current& c)
{
	unsigned int i;
	Collaboration::ListOfStrings usr;
	Collaboration::MIUser usuario;
	
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		Collaboration::ListOfUsers v = MIApplication::getNonUpdatedUsers(apl);
		if (v.size() > 0) 
		{
			for (i = 0; i < v.size(); i++)
			{
				usr.push_back(v[i].name);
			}
		}
	}
	
	return usr;
}

Collaboration::ListOfStrings MIDataAccessor_impl::applicationRoles(const ::std::string& app, const Ice::Current& c)
{
	unsigned int i;
	Collaboration::ListOfRoles v;
	Collaboration::ListOfStrings rs;
	Collaboration::MIRole rol;
	
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		v = apl.roles;
		if (v.size()>0)
		{ 
			for (i = 0; i < v.size(); i++)
			{
				rs.push_back(v[i].name);
			}
		}
	}
	return rs;
}

Collaboration::ListOfStrings MIDataAccessor_impl::applicationUsers(const ::std::string& app, const Ice::Current& c)
{
	unsigned int i;
	Collaboration::ListOfStrings usr;
	
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		if (apl.users.size()>0)
		{ 
			for (i = 0; i < apl.users.size(); i++)
			{
				usr.push_back(apl.users[i].name);
			}
		}
	}
	return usr;
}

Collaboration::ListOfStrings MIDataAccessor_impl::applicationComponents(const ::std::string& app, const Ice::Current& c)
{
	unsigned int i;
	Collaboration::ListOfComponents v;
	Collaboration::ListOfStrings rs;
	
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		v = apl.components;
		if (v.size()>0)
		{ 
			for (i = 0; i < v.size(); i++)
			{	
				rs.push_back(v[i].name);
			}
		}
	}
	return rs;
}

Collaboration::ListOfRoles MIDataAccessor_impl::allowedRoles(const ::std::string& app, 
															const ::std::string& user, 
															const Ice::Current& c)
{
	unsigned int i;
	Collaboration::ListOfRoles todos = rolesInfo(app, c);
	Collaboration::ListOfRoles res;
	Collaboration::MIUser u_aux;
	
	int pos = getApplicationPos(app);
	if ( (todos.size()>0) && (pos != -1) )
	{
		Collaboration::MIApplication apl = m_applications[pos];
		pos = getUser(apl, user);
		if (pos != -1)
		{
			for (i=0; i<todos.size(); i++)
			{
				if (MIUser::hasAllowedRole(apl.users[pos], todos[i].name))
				{
					res.push_back(todos[i]); 
				}
			}
			
			return res;
		}
	}
	
	Collaboration::ListOfRoles vacio;
	return vacio;
}

Collaboration::ListOfStrings MIDataAccessor_impl::allowedRoleNames(const ::std::string& app, 
																	const ::std::string& user,
																	const Ice::Current& c)
{
	Collaboration::ListOfStrings vacia;
	
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		pos = getUser(apl, user);
		if (pos != -1)
		{
			return apl.users[pos].allowedRoles;
		}
	}
	return vacia;
}

int MIDataAccessor_impl::getUserComponentPermissions(const ::std::string& app, 
													const ::std::string& user, 
													const ::std::string& comp,
													const Ice::Current& c)
{
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		return MIApplication::userComponentPermissions(apl, user, comp);
	}
	else return -1;
}

bool MIDataAccessor_impl::setUserComponentPermissions(const ::std::string& app, 
													const ::std::string& user, 
													const ::std::string& comp, 
													int level,
													const Ice::Current& c)
{
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		return MIApplication::setUserComponentPermissions(apl, user, comp, level);
	}
	else return false;
}

int MIDataAccessor_impl::getRoleComponentPermissions(const ::std::string& app, 
													const ::std::string& role, 
													const ::std::string& comp,
													const Ice::Current& c)
{
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		return MIApplication::roleComponentPermissions(apl, role, comp);
	}
	else return -1;
}

bool MIDataAccessor_impl::setRoleComponentPermissions(const ::std::string& app, 
														const ::std::string& role, 
														const ::std::string& comp, 
														int level,
														const Ice::Current& c)
{
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		return MIApplication::setRoleComponentPermissions(apl, role, comp, level);
	}
	else return false;
}

::std::string MIDataAccessor_impl::userActualRole(const ::std::string& app, 
										const ::std::string& user, 
										const Ice::Current& c)
{
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		return MIApplication::getActualUserRole(apl, user);
	}
	
	return "";
}

bool MIDataAccessor_impl::newUserAllowedRole(const ::std::string& app, 
											const ::std::string& user, 
											const ::std::string& role,
											const Ice::Current& c)
{
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		return MIApplication::addUserAllowedRole(apl, user, role);
	}
		
	return false;
}

bool MIDataAccessor_impl::newUser(const ::std::string& app, 
								const ::std::string& user, 
								const ::std::string& password, 
								const ::std::string& default_role, 
								bool is_admin,
								const Ice::Current& c)
{
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		Collaboration::MIUser usr;
		usr.name = user;
		usr.password = password;
		usr.defaultRole = default_role;
		usr.isAdmin = is_admin;
		
		return MIApplication::addUser(apl, usr);
	}
	else return false;
}

bool MIDataAccessor_impl::newRole(const ::std::string& app, const ::std::string& role, const Ice::Current& c)
{
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		Collaboration::MIRole rol;
		rol.name = role;
		
		return MIApplication::addRole(apl, rol);
	}
	else return false;
}

bool MIDataAccessor_impl::removeAllowedUserRole(const ::std::string& app, 
												const ::std::string& user, 
												const ::std::string& role, 
												const Ice::Current& c)
{
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		return MIApplication::removeUserAllowedRole(apl, user, role);
	}
	
	else return false;
}

bool MIDataAccessor_impl::removeUser(const ::std::string& app, 
									const ::std::string& user, 
									const Ice::Current& c)
{
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		return MIApplication::removeUser(apl, user);
	}
	else return false;
}

bool MIDataAccessor_impl::removeRole(const ::std::string& app, 
									const ::std::string& role, 
									const Ice::Current& c)
{
	int pos = getApplicationPos(app);
	if (pos != -1)
	{
		Collaboration::MIApplication apl = m_applications[pos];
		return MIApplication::removeRole(apl, role);
	}
	else return false;
}

Collaboration::ListOfStrings MIDataAccessor_impl::getApplicationsNames(const Ice::Current& c)
{
	unsigned int i;
	Collaboration::ListOfStrings res;
	
	for (i=0; i<m_applications.size(); i++)
	{
		res.push_back(m_applications[i].name);
	}
	
	return res;
}

Collaboration::MIApplication MIDataAccessor_impl::getApplication(const ::std::string& name, const Ice::Current& c)
{
	unsigned int i;
	Collaboration::MIApplication aux;
	
	for (i=0; i<m_applications.size(); i++)
	{
		if ( (!m_applications[i].name.empty()) && (m_applications[i].name == name) )
		{
			return m_applications[i];
		}
	}

	return aux;
}

void MIDataAccessor_impl::commit(const Ice::Current& c)
{
	m_reader.set(m_applications);
}
